package org.ns.basics.commons.trace;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;

public class TraceExecutors {
	/**
	 * Creates a thread pool that reuses a fixed number of threads operating off a
	 * shared unbounded queue. At any point, at most {@code nThreads} threads will
	 * be active processing tasks. If additional tasks are submitted when all
	 * threads are active, they will wait in the queue until a thread is available.
	 * If any thread terminates due to a failure during execution prior to shutdown,
	 * a new one will take its place if needed to execute subsequent tasks. The
	 * threads in the pool will exist until it is explicitly
	 * {@link ExecutorService#shutdown shutdown}.
	 *
	 * @param nThreads the number of threads in the pool
	 * @return the newly created thread pool
	 * @throws IllegalArgumentException if {@code nThreads <= 0}
	 */
	public static ExecutorService newFixedThreadPool(int nThreads) {
		return TraceUtils.trace(Executors.newFixedThreadPool(nThreads));
	}

	/**
	 * Creates a thread pool that maintains enough threads to support the given
	 * parallelism level, and may use multiple queues to reduce contention. The
	 * parallelism level corresponds to the maximum number of threads actively
	 * engaged in, or available to engage in, task processing. The actual number of
	 * threads may grow and shrink dynamically. A work-stealing pool makes no
	 * guarantees about the order in which submitted tasks are executed.
	 *
	 * @param parallelism the targeted parallelism level
	 * @return the newly created thread pool
	 * @throws IllegalArgumentException if {@code parallelism <= 0}
	 * @since 1.8
	 */
	public static ExecutorService newWorkStealingPool(int parallelism) {
		return TraceUtils.trace(Executors.newWorkStealingPool(parallelism));
	}

	/**
	 * Creates a work-stealing thread pool using all
	 * {@link Runtime#availableProcessors available processors} as its target
	 * parallelism level.
	 * 
	 * @return the newly created thread pool
	 * @see #newWorkStealingPool(int)
	 * @since 1.8
	 */
	public static ExecutorService newWorkStealingPool() {
		return TraceUtils.trace(Executors.newWorkStealingPool());
	}

	/**
	 * Creates a thread pool that reuses a fixed number of threads operating off a
	 * shared unbounded queue, using the provided ThreadFactory to create new
	 * threads when needed. At any point, at most {@code nThreads} threads will be
	 * active processing tasks. If additional tasks are submitted when all threads
	 * are active, they will wait in the queue until a thread is available. If any
	 * thread terminates due to a failure during execution prior to shutdown, a new
	 * one will take its place if needed to execute subsequent tasks. The threads in
	 * the pool will exist until it is explicitly {@link ExecutorService#shutdown
	 * shutdown}.
	 *
	 * @param nThreads      the number of threads in the pool
	 * @param threadFactory the factory to use when creating new threads
	 * @return the newly created thread pool
	 * @throws NullPointerException     if threadFactory is null
	 * @throws IllegalArgumentException if {@code nThreads <= 0}
	 */
	public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
		return TraceUtils.trace(Executors.newFixedThreadPool(nThreads, threadFactory));
	}

	/**
	 * Creates an Executor that uses a single worker thread operating off an
	 * unbounded queue. (Note however that if this single thread terminates due to a
	 * failure during execution prior to shutdown, a new one will take its place if
	 * needed to execute subsequent tasks.) Tasks are guaranteed to execute
	 * sequentially, and no more than one task will be active at any given time.
	 * Unlike the otherwise equivalent {@code newFixedThreadPool(1)} the returned
	 * executor is guaranteed not to be reconfigurable to use additional threads.
	 *
	 * @return the newly created single-threaded Executor
	 */
	public static ExecutorService newSingleThreadExecutor() {
		return TraceUtils.trace(Executors.newSingleThreadExecutor());
	}

	/**
	 * Creates an Executor that uses a single worker thread operating off an
	 * unbounded queue, and uses the provided ThreadFactory to create a new thread
	 * when needed. Unlike the otherwise equivalent
	 * {@code newFixedThreadPool(1, threadFactory)} the returned executor is
	 * guaranteed not to be reconfigurable to use additional threads.
	 *
	 * @param threadFactory the factory to use when creating new threads
	 *
	 * @return the newly created single-threaded Executor
	 * @throws NullPointerException if threadFactory is null
	 */
	public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
		return TraceUtils.trace(Executors.newSingleThreadExecutor(threadFactory));
	}

	/**
	 * Creates a thread pool that creates new threads as needed, but will reuse
	 * previously constructed threads when they are available. These pools will
	 * typically improve the performance of programs that execute many short-lived
	 * asynchronous tasks. Calls to {@code execute} will reuse previously
	 * constructed threads if available. If no existing thread is available, a new
	 * thread will be created and added to the pool. Threads that have not been used
	 * for sixty seconds are terminated and removed from the cache. Thus, a pool
	 * that remains idle for long enough will not consume any resources. Note that
	 * pools with similar properties but different details (for example, timeout
	 * parameters) may be created using {@link ThreadPoolExecutor} constructors.
	 *
	 * @return the newly created thread pool
	 */
	public static ExecutorService newCachedThreadPool() {
		return TraceUtils.trace(Executors.newCachedThreadPool());
	}

	/**
	 * Creates a thread pool that creates new threads as needed, but will reuse
	 * previously constructed threads when they are available, and uses the provided
	 * ThreadFactory to create new threads when needed.
	 * 
	 * @param threadFactory the factory to use when creating new threads
	 * @return the newly created thread pool
	 * @throws NullPointerException if threadFactory is null
	 */
	public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
		return TraceUtils.trace(Executors.newCachedThreadPool(threadFactory));
	}

	/**
	 * Creates a single-threaded executor that can schedule commands to run after a
	 * given delay, or to execute periodically. (Note however that if this single
	 * thread terminates due to a failure during execution prior to shutdown, a new
	 * one will take its place if needed to execute subsequent tasks.) Tasks are
	 * guaranteed to execute sequentially, and no more than one task will be active
	 * at any given time. Unlike the otherwise equivalent
	 * {@code newScheduledThreadPool(1)} the returned executor is guaranteed not to
	 * be reconfigurable to use additional threads.
	 * 
	 * @return the newly created scheduled executor
	 */
	public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
		return TraceUtils.trace(Executors.newSingleThreadScheduledExecutor());
	}

	/**
	 * Creates a single-threaded executor that can schedule commands to run after a
	 * given delay, or to execute periodically. (Note however that if this single
	 * thread terminates due to a failure during execution prior to shutdown, a new
	 * one will take its place if needed to execute subsequent tasks.) Tasks are
	 * guaranteed to execute sequentially, and no more than one task will be active
	 * at any given time. Unlike the otherwise equivalent
	 * {@code newScheduledThreadPool(1, threadFactory)} the returned executor is
	 * guaranteed not to be reconfigurable to use additional threads.
	 * 
	 * @param threadFactory the factory to use when creating new threads
	 * @return a newly created scheduled executor
	 * @throws NullPointerException if threadFactory is null
	 */
	public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
		return TraceUtils.trace(Executors.newSingleThreadScheduledExecutor(threadFactory));
	}

	/**
	 * Creates a thread pool that can schedule commands to run after a given delay,
	 * or to execute periodically.
	 * 
	 * @param corePoolSize the number of threads to keep in the pool, even if they
	 *                     are idle
	 * @return a newly created scheduled thread pool
	 * @throws IllegalArgumentException if {@code corePoolSize < 0}
	 */
	public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
		return TraceUtils.trace(Executors.newScheduledThreadPool(corePoolSize));
	}

	/**
	 * Creates a thread pool that can schedule commands to run after a given delay,
	 * or to execute periodically.
	 * 
	 * @param corePoolSize  the number of threads to keep in the pool, even if they
	 *                      are idle
	 * @param threadFactory the factory to use when the executor creates a new
	 *                      thread
	 * @return a newly created scheduled thread pool
	 * @throws IllegalArgumentException if {@code corePoolSize < 0}
	 * @throws NullPointerException     if threadFactory is null
	 */
	public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
		return TraceUtils.trace(Executors.newScheduledThreadPool(corePoolSize, threadFactory));
	}

}
